
/***
 * @Description: 负责内存存储的管理，对固定长度的存储分配，包括数据包需要的空白链表的获取，释放，内存锁的应用C语言文件
 * @Author: Liverpool
 * @Date: 2024-02-21 22:33:55
 * @LastEditTime: 2024-02-21 22:37:57
 * @LastEditors: Liverpool
 */
#include "memory_block.h"

/***
 * @description: 对连续的空闲内存数组进行固定长度的链表初始化
 * @Author: Liverpool
 * @Date: 2024-02-28 01:13:23
 * @return {*}
 * @param {D_MemoryBlock} *block 需要初始化的内存链表数据头
 * @param {void} *memory 需要进行内存链表化的结构性数组的头地址
 * @param {int} block_size 每一个空闲数据块的链表长度
 * @param {int} block_cnt 内存链表中的链表节点
 * @param {D_LockerType} locker_type 对该空闲链表使用的锁的类型
 */
net_err_t memory_block_init(D_MemoryBlock *block, void *memory, int block_size, int block_cnt, D_LockerType locker_type)
{
    uint8_t *buffer = (uint8_t *)memory; // 使用buffer(字节指针)指向需要分配的内存空间
    list_init(&block->free_list);        // 初始化空闲链表头
    for (int i = 0; i < block_cnt; i++, buffer += block_size)
    {
        // 初始化空闲链表的结点
        D_ListNode *block_node = (D_ListNode *)buffer;
        list_node_init(block_node);
        list_insert_last(&block->free_list, block_node); // 在链表后面插入空闲内存块
    }
    // 对锁进行初始化
    net_err_t locker_err = locker_init(&block->locker, locker_type);
    if (locker_err < 0)
    {
        debug_error(Debug_MemoryBlock, "create locker fail!");
        return locker_err;
    }
    // 对信号量进行初始化
    if (locker_type != Locker_Self)
    {
        block->alloc_sem = sys_sem_create(block_cnt);
        if (block->alloc_sem == SYS_SEM_INVALID)
        {
            debug_error(Debug_MemoryBlock, "create sem fail!");
            return NET_ERR_SYS;
        }
    }
    return NET_ERR_OK;
}

/***
 * @description: 分配空闲的内存链表结点
 * @Author: Liverpool
 * @Date: 2024-03-01 00:24:16
 * @return {*} 分配出去的结点地，如果分配失败那就返回空地址
 * @param {D_MemoryBlock} *block 需要分配的空闲链表头地址
 * @param {int} ms 最多等待分配内存块的时间(ms) 0:代表一直等 >0:才会等相应的时间
 */
void *memory_block_alloc(D_MemoryBlock *block, int ms)
{
    // 第一种情况：没有等待时间或该内存链表锁是在单一线程中使用
    if ((ms < 0) || (block->locker.type == Locker_Self))
    {
        locker_lock(&block->locker); // 上锁
        int count = list_get_count(&block->free_list);
        if (count == 0)
        {
            locker_Unlock(&block->locker); // 解锁
            return (void *)0;              // 返回空地址
        }
        else
        {
            D_ListNode *block_node = list_remove_first(&block->free_list); // 移除链表的头结点作为可供分配的内存块
            locker_Unlock(&block->locker);                                 // 解锁
            return block_node;
        }
    }
    else // 第二种情况：该内存链表在不同线程之间使用或有相应的需要等待分配的时间
    {
        if (sys_sem_wait(block->alloc_sem, ms) < 0) // 等待时间超时
        {
            return (void *)0;
        }
        else
        {
            locker_lock(&block->locker);                                   // 上锁
            D_ListNode *block_node = list_remove_first(&block->free_list); // 移除链表的头结点作为可供分配的内存块
            locker_Unlock(&block->locker);                                 // 解锁
            return block_node;
        }
    }
}
/***
 * @description: 得到该内存链表中剩余的空闲结点数
 * @Author: Liverpool
 * @Date: 2024-03-01 00:24:22
 * @return {*} 剩余的空闲结点数
 * @param {D_MemoryBlock} *block 需要查询的内存链表头
 */
int memory_block_free_cnt(D_MemoryBlock *block)
{
    locker_lock(&block->locker);                   // 上锁
    int count = list_get_count(&block->free_list); // 查询链表中剩余的结点数
    locker_Unlock(&block->locker);                 //  解锁
    return count;
}

/***
 * @description: 释放内存块到内存管理链表中
 * @Author: Liverpool
 * @Date: 2024-03-01 01:31:18
 * @return {*}
 * @param {D_MemoryBlock} *block 内存管理链表地址
 * @param {void} *block_node 需要释放的内存块地址
 */
void memory_block_free(D_MemoryBlock *block, void *block_node)
{
    locker_lock(&block->locker);                                   // 上锁
    list_insert_last(&block->free_list, (D_ListNode *)block_node); // 把需要释放的内存块直接插入到内存管理链表的最后面
    locker_Unlock(&block->locker);                                 //  解锁
    if (block->locker.type != Locker_Self)
    {
        sys_sem_notify(&block->alloc_sem); // 如果该内存管理链表使用在多线程中那就需要释放信号量
    }
}
/***
 * @description: 销毁该内存管理链表
 * @Author: Liverpool
 * @Date: 2024-03-01 01:31:45
 * @return {*}
 * @param {D_MemoryBlock} *block 内存管理链表地址
 */
void memory_block_destroy(D_MemoryBlock *block)
{
    if (block->locker.type != Locker_Self) // 只有该链表在多个线程之间使用的时候才需要销魂信号量和锁
    {
        sys_sem_free(block->alloc_sem);
        locker_destroy(&block->locker);
    }
}